package com.foreveross.bsl.push.repository.custom.impl;

import java.util.Collection;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import com.foreveross.bsl.push.domain.entity.Push;
import com.foreveross.bsl.push.domain.entity.Push.PushStatusEnum;
import com.foreveross.bsl.push.repository.custom.PushRepositoryCustom;

public class PushRepositoryImpl implements PushRepositoryCustom {
	
	private static final Logger log = LoggerFactory.getLogger(PushRepositoryImpl.class);

	@Autowired
	private MongoTemplate mongoTemplate;
	
	@Override
	public void findAndUpdateToSendingByIds(Date sendingTime, Collection<String> pushIds) {
		for(String pId : pushIds){
			Push push=this.mongoTemplate.findById(pId, Push.class);
			if(push!=null){
				if(push.getStatus().ordinal()>=PushStatusEnum.SENDING.ordinal()){
					return;
				}
				push.setStatus(PushStatusEnum.SENDING);
				push.setSendingTime(sendingTime);
				this.mongoTemplate.save(push);
			}
		}
	}

	@Override
	public void findAndUpdateToSentByIds(Date sentTime, Collection<String> pushIds) {
		for(String pId : pushIds){
			Push push=this.mongoTemplate.findById(pId, Push.class);
			if(push!=null){
				if(push.getStatus().ordinal()>=PushStatusEnum.SENT.ordinal()){
					return;
				}
				push.setStatus(PushStatusEnum.SENT);
				push.setSentTime(sentTime);
				this.mongoTemplate.save(push);
			}
		}
	}

	@Override
	public void findAndUpdateToOfflineByIds(Collection<String> pushIds, String errorMsg) {
		Query query = Query.query(Criteria.where("id").in(pushIds));
		Update update = Update.update("status", PushStatusEnum.OFFLINE).set("lastErrorMsg", errorMsg);
		this.mongoTemplate.updateMulti(query, update, Push.class);
		log.debug("更新{}个推送为OFFLINE状态", pushIds.size());
	}

	@Override
	public void findAndUpdateToFailureByIds(Collection<String> pushIds, String errorMsg) {
		Query query = Query.query(Criteria.where("id").in(pushIds));
		Update update = Update.update("status", PushStatusEnum.FAILURE).set("lastErrorMsg", errorMsg);
		this.mongoTemplate.updateMulti(query, update, Push.class);
		log.debug("更新{}个推送为FAILURE状态", pushIds.size());
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.foreveross.bsl.push.repository.custom.PushRepositoryCustom#
	 * findByDeviceIdAndSendId(java.lang.String, java.lang.String)
	 */
	@Override
	public Push findOne(String appId, String deviceId, String pushRequestId) {
		Criteria cri = new Criteria();
		cri.and("request.$id").is(pushRequestId).and("target.deviceId").is(deviceId).and("target.appId").is(appId);
		Push push = this.mongoTemplate.findOne(Query.query(cri), Push.class);
		return push;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.foreveross.bsl.push.repository.custom.PushRepositoryCustom#
	 * findOfflinePushs(java.lang.String, java.lang.String)
	 */
	@Override
	public Push findOfflinePush(String appId, String deviceId) {
		Validate.notEmpty(appId, "appId不能为空");
		Validate.notEmpty(deviceId, "deviceId不能为空");
		final Date now = new Date();
		Criteria cri = Criteria.where("target.appId").is(appId).and("status").is(Push.PushStatusEnum.OFFLINE).and("expiredTime")
				.gte(now);
		if (!StringUtils.isEmpty(deviceId)) {
			cri.and("target.deviceId").is(deviceId);
		}
		return this.mongoTemplate.findOne(Query.query(cri), Push.class);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.foreveross.bsl.push.repository.custom.PushRepositoryCustom#
	 * findExpiredPushs()
	 */
	@Override
	public List<Push> findExpiredLivePushs() {
		final Date now = new Date();
		Criteria cri = Criteria.where("status")
				.nin(Push.PushStatusEnum.FAILURE, Push.PushStatusEnum.RECEIPT, Push.PushStatusEnum.CANCEL).and("expiredTime")
				.lt(now);
		return this.mongoTemplate.find(Query.query(cri), Push.class);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.foreveross.bsl.push.repository.custom.PushRepositoryCustom#
	 * findValidSentAndNoReceiptPushs(java.lang.String, java.lang.String)
	 */
	@Override
	public Page<Push> findValidSentAndNoReceiptPushs(String deviceId, String appId, Pageable pageable) {
		final Date now = new Date();
		Criteria cri = Criteria.where("target.deviceId").is(deviceId)
				.and("target.appId").is(appId)
				.and("status").is(Push.PushStatusEnum.SENT)
				.and("expired_time").gte(now);
		Query query=Query.query(cri).with(pageable).with(new Sort("create_time"));
		long c = mongoTemplate.count(query, Push.class);
		List<Push> list = mongoTemplate.find(query, Push.class);
		return new PageImpl<Push>(list, pageable, c);
	}
	
}
